package go_im

import (
	"fmt"
	"io"
	"net"
	"sync"
	"time"
)

const INTERVAL = 30

type Server struct {
	Ip   string
	Port int
	//在线用户列表
	OnlineMap map[string]*User
	mapLock   sync.RWMutex

	//消息广播的channel
	Message chan string
}

func (server *Server) handler(conn net.Conn) {
	//当前连接的服务
	//fmt.Println("连接创建成功:", conn.RemoteAddr().String())

	//用户上线,将用户加入到OnlineMap中
	user := NewUser(conn, server)
	user.Online()

	isLive := make(chan bool)

	//接收客户端发送的消息
	go func() {
		buf := make([]byte, 4096)
		n, err := conn.Read(buf)
		//在TCP协议中，当一方的socket关闭时，另一方的socket会收到一个FIN包，表示连接被关闭。此时conn.Read()方法返回0，表示连接已经断开。
		if n == 0 {
			user.Offline()
			return
		}

		if err != nil && err != io.EOF {
			fmt.Println("Conn Read err:", err)
			user.Offline()
			return
		}

		//去除\n
		msg := string(buf[:n-1])
		user.DoMessage(msg)

		//用户发送了任意消息,代表用户是活跃的
		isLive <- true
	}()

	//当前handler阻塞 这个 select 语句没有 case，因此它会永远阻塞，不会退出
	//为了防止函数 handler() 提前返回而保持 goroutine 的活动状态。
	//select {}

	timer := time.NewTimer(INTERVAL * time.Second)
	for {
		select {
		case <-isLive:
			//当前用户是活跃的,应当重置定时器
			if !timer.Stop() {
				//定时器已经触发过,需要将过期的时间从 channel 中删除
				<-timer.C
			}
			timer.Reset(INTERVAL * time.Second)
		case <-timer.C:
			//已经超时踢出用户
			user.SendMessage("你已超时,请重新登录")
			user.Offline()
			err := user.conn.Close()
			if err != nil {
				return
			}
		}
	}
}

func (server *Server) ListenMessage() {
	for {
		msg := <-server.Message
		//将msg发送给全部在线user
		server.mapLock.Lock()
		for _, cli := range server.OnlineMap {
			cli.Ch <- msg
		}
		server.mapLock.Unlock()
	}
}

func (server *Server) BroadCast(user *User, msg string) {
	sendMsg := "[" + user.Name + "]" + ":" + msg

	server.Message <- sendMsg
	//server.mapLock.Lock()
	//for _, cli := range server.OnlineMap {
	//	cli.Ch <- sendMsg
	//}
	//server.mapLock.Unlock()
}

func NewServer(ip string, port int) *Server {
	return &Server{
		Ip:        ip,
		Port:      port,
		OnlineMap: make(map[string]*User, 32),
		Message:   make(chan string),
	}
}

func (server *Server) Start() {
	//socket listen this.Ip+":"+strconv.Itoa(this.Port)
	listen, err := net.Listen("tcp", fmt.Sprintf("%s:%d", server.Ip, server.Port))
	if err != nil {
		fmt.Println("listen error:" + err.Error())
		return
	}

	defer func(listen net.Listener) {
		err := listen.Close()
		if err != nil {
			fmt.Println("close listen error:" + err.Error())
		}
	}(listen)

	//启动监听Message的goroutine
	go server.ListenMessage()

	for {
		//accept
		conn, err := listen.Accept()
		if err != nil {
			fmt.Println("accept error:" + err.Error())
			continue
		}
		//do handler
		go server.handler(conn)
	}
}
